package simu;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import simu.nodes.MasterNode;
import simu.nodes.Node;

/**
 * Class VesoMeshSimulator is used to implement the logic
 * the application that manages the VESO Mesh Simulator
 * 
 * @author Edwin Flórez G.
 * 
 * Final project ICOM6089
 *
 */

public class VesoMeshSimulator {
	
	// Constants to define the services available,
    // Add a new node
    private static final int ADD_NODE = 1;
    // Remove a node
    private static final int REM_NODE = 2;
    // View a node
    private static final int VIEW_NODE = 3;
    // Print all nodes
    private static final int PRINT_NODES = 4;
    // Start sensor from a given node
    private static final int START_SENSOR = 5;
    // Stop sensors from a given node
    private static final int STOP_SENSORS = 6;
    // Print all files from a give node
    private static final int PRINT_FILES_NODE = 7;
    // Print all files 
    private static final int PRINT_FILES = 8;
    // Add a gadget to a node
    private static final int ADD_GADGET_NODE = 9;
    // Finish
    private static final int DONE = 15;
    
    // Simulator Manager object that keeps track if the data
    // in the simulator and provides the operations to make ...
    private MasterNode myMasterNode;

	/*
	 * Default constructor used to create a new 
	 * instance of VesoMeshSimulator.
	 */
    private VesoMeshSimulator(){
    	myMasterNode = MasterNode.getInstance();
    }
    
    /*
     * Function used to start the execution of the application.
     */
    
    private void start() throws Exception {
    	
        boolean done = false;
        int option = 0;
        
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        
        System.out.println("Welcome to the Veso Mesh Application");
        
        while(!done){
        	try {
        		printMenu();
        		option = getUserOption(in);
        		switch(option){
	        		case ADD_NODE:
	        			handleAddNode(in);
	        			break;
	        		case REM_NODE:
	        			//handleRemoveNode(in);
	        			break;
	        		case VIEW_NODE:
	        			//handleViewNode(in);
	        			break;
	        		case PRINT_NODES:
	        			handlePrintNodes();
	        			break;
	        		case START_SENSOR:
	        			handleStartSensor(in);
	        			break;
	        		case STOP_SENSORS:
	        			handleStopSensors(in);
	        			break;
	        		case PRINT_FILES_NODE:
	        			handlePrintFilesNode(in);
	        			break;
	        		case PRINT_FILES:
	        			handlePrintAllSystemFiles();
	        			break;
	        		case ADD_GADGET_NODE:
	        			handleAddGadgetNode(in);
	        			break;
	        		case DONE:
	        			done = true;
	        			//handleDone();
	        			break;  
	        		default:
	        			System.out.println("Illegal option: " + option);
	        			break;
        		}
        	}
        	catch (Exception e) {
        		//e.printStackTrace();
        		System.out.println("Illegal option try again...");
        	}
        }
    }

    
    /**
     * @param in
     */
    private void handleAddGadgetNode(BufferedReader in) throws IOException{
        String nodeToAddGadget = null;
        
        // Get node to add gadget 
        System.out.println("Enter the index node to add gadget: ");
        nodeToAddGadget =  in.readLine();
        int option = Integer.parseInt(nodeToAddGadget);
    
    }
    
    /**
     * @param in
     */
    private void handleAddNode(BufferedReader in) throws IOException{
        String nodeType = null;
        
        // Get the type of node to create from user 
        System.out.println("Enter the node type to add (procnode(1), simplenode(2), apnode(3)): ");
        nodeType =  in.readLine();
        int option = Integer.parseInt(nodeType);
        switch (option) {
	        case 1: 	
	        	myMasterNode.addNode(1);
	        	break;
	        case 2:	
	        	myMasterNode.addNode(2);
	        	break;
	        case 3: 		
	        	myMasterNode.addNode(3);
	        	break;
	        default:
	        	System.out.println("Illegal option: " + nodeType + ", going back.");
	        	break;
        }    
    }
    
    private void handlePrintNodes(){
    	ArrayList<Node> tempArray = myMasterNode.getNodes();
        System.out.println("There are "+tempArray.size()+" nodes.");
    	for (Node  e: tempArray) {
			System.out.println(e);
		}
    }
    
    /**
     * @param in
     */
    private void handlePrintFilesNode(BufferedReader in) throws IOException{
    	String indexNode = null;
    	
    	// Get the index of node 
        System.out.println("Enter index of node to get files: ");
        indexNode =  in.readLine();
    	int index = Integer.parseInt(indexNode);
        
        String[] tempArray = myMasterNode.getFiles(index);
        printFiles(tempArray, index);  
    }

    private void handlePrintAllSystemFiles() throws IOException{
    	
    	ArrayList<String[]> systemFiles = myMasterNode.getAllFiles(); 
    	System.out.println("There are "+systemFiles.size()+" nodes.");
    	for (int i = 0; i < systemFiles.size(); i++){
    		System.out.println("_____________________________________");
    		printFiles(systemFiles.get(i),i);
    	}
    	
    }
    
    //Auxiliary method to print files from a node index. 
    private void printFiles(String[] files, int index){
    	System.out.println("The node with index "+index+" has "+files.length+" files.");
        int counter = 0;
        for ( String  e: files ) {
        	counter++;
			System.out.println(counter+": "+e);
		}
    }
    
    /**
     * @param in
     */
    private void handleStartSensor(BufferedReader in) throws IOException{
    	String indexNode = null;
    	String sensor = null;
    	
    	// Get the index of node 
        System.out.println("Enter index of node: ");
        indexNode =  in.readLine();
        int index = Integer.parseInt(indexNode);
        System.out.println("Enter sensor's name (audio, video, picture): ");
        sensor =  in.readLine();
        myMasterNode.getNode(index).startSensor(sensor);
    }
    
    /**
     * @param in
     */
    private void handleStopSensors(BufferedReader in) throws IOException{
    	String indexNode = null;
    	
    	// Get the index of node 
        System.out.println("Enter index of node: ");
        indexNode =  in.readLine();
        myMasterNode.getNode(Integer.parseInt(indexNode)).stopSensors();
    }
    
    
    /*
     * Function used to print the options available to the user.
     */
    private void printMenu(){
    	System.out.println("*************************************");
    	System.out.println("1. Add Node");
    	System.out.println("2. Remove Node");
    	System.out.println("3. View Node information");
    	System.out.println("4. Print all Nodes");
    	System.out.println("5. Start sensor from a given node");
    	System.out.println("6. Stop sensors from a given node");
    	System.out.println("7. Print all Files from Node");
    	System.out.println("8. Print all Files");
    	System.out.println("9. Add a gadget to a node");
    	System.out.println("15. Exit");
    	System.out.println("*************************************");
    }
    
    /*
     * Function used to get the input from the user.
     */
 	private int getUserOption(BufferedReader in) throws IOException{
 		
 		String value = null;
 		
 		System.out.println("Enter your option: ");
 		value = in.readLine();
 		if (value.equals("1")){
 			return 1;
 		}
 		else if (value.equals("2")){
 			return 2;
 		}
 		else if (value.equals("3")){
 			return 3;
 		}
 		else if (value.equals("4")){
 			return 4;
 		}
 		else if (value.equals("5")){
 			return 5;
 		}
 		else if (value.equals("6")){
 			return 6;
 		}
 		else if (value.equals("7")){
 			return 7;
 		}
 		else if (value.equals("8")){
 			return 8;
 		}
 		else if (value.equals("9")){
 			return 9;
 		}
 		else if (value.equals("15")){
 			return 15;
 		}
 		else {
 			throw new UnsupportedOperationException("Illegal option:" + value);
 		}
 	}
    
	public static void main(String[] args) {
		VesoMeshSimulator application = new VesoMeshSimulator();
		try {
			application.start();
		}
		catch (Exception e){
			e.printStackTrace();
		}

	}

}
